package com.scratch.terminal.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Snowflake;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.fastjson.JSON;
import com.scratch.common.cache.constant.CacheConstants;
import com.scratch.common.contant.CommonContant;
import com.scratch.common.core.utils.core.StrUtil;
import com.scratch.common.core.web.enums.ErrorCode;
import com.scratch.common.core.web.result.R;
import com.scratch.common.redis.constant.RedisConstants;
import com.scratch.common.redis.service.RedisService;
import com.scratch.common.service.CommonService;
import com.scratch.common.service.db.DbUtils;
import com.scratch.common.service.db.domain.BaseCashEntity;
import com.scratch.common.service.db.domain.BaseOrderEntity;
import com.scratch.common.service.db.domain.BaseTicketLoadEntity;
import com.scratch.common.utils.QrCodeUtil;
import com.scratch.core.api.AuthDto;
import com.scratch.core.api.cp.domain.dto.BaseCpDto;
import com.scratch.core.api.org.domain.dto.BaseOrgDto;
import com.scratch.core.api.service.domain.*;
import com.scratch.core.api.site.domain.dto.BaseSiteDto;
import com.scratch.core.api.terminalModel.domain.dto.BaseTerminalModelDto;
import com.scratch.core.api.ticket.domain.dto.BaseTicketDto;
import com.scratch.core.enums.*;
import com.scratch.terminal.service.ITerminalService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
@Slf4j
public class TerminalService implements ITerminalService {
    private static Integer initStatus = 1;

    @Autowired
    private RedisService redisService;

    @Autowired
    private CommonService commonService;

    @Autowired
    private Snowflake snowflake;

    @Override
    public R playList(ReqPlayList reqPlayList) {
        R r = commonService.sellAuthCheck(reqPlayList.getDevNo());
        if (r.isFail()) {
            return r;
        }
        List<ResPlayList> resPlayLists = ListUtil
                .sortByProperty(commonService.getTicketList(r), "id")
                .stream().map(baseTicketDto -> {
                    ResPlayList resPlayList = BeanUtil.copyProperties(baseTicketDto, ResPlayList.class);
                    resPlayList.setTicketId((baseTicketDto).getId().toString());
                    return resPlayList;
                }).collect(Collectors.toList());
        Collections.reverse(resPlayLists);
        return R.ok(Objects.isNull(reqPlayList.getValue()) ? resPlayLists : resPlayLists.stream().filter(x -> x.getValue() == reqPlayList.getValue()).collect(Collectors.toList()));
    }

    @Override
    public R loadTickets(ReqTicketLoad reqTicketLoad) {
        R r = commonService.sellAuthCheck(reqTicketLoad.getDevNo());
        if (r.isFail()) {
            return r;
        }
        AuthDto authDto = (AuthDto) r.getData();
        List<Object> sellAuthCheck = authDto.getSiteAuthSellPlayList();
        if (!sellAuthCheck.contains(reqTicketLoad.getTicketId())) {
            return R.fail(ErrorCode.TERMINAL_LOADTICKETS_TICKETID);
        }
        //仓位
        BaseTerminalModelDto baseTerminalModelDto = commonService.getTerminalModel(String.valueOf(authDto.getBaseTerminalDto().getModelId()));
        String hp = baseTerminalModelDto.getHp();
        if (StringUtils.isBlank(hp)) {
            return R.fail(ErrorCode.TERMINAL_LOADTICKETS_HP_CONFIG);
        }
        Integer row = Integer.parseInt(hp.split(",")[0]);
        Integer column = Integer.parseInt(hp.split(",")[1]) - 1;
        if (reqTicketLoad.getHpId() > row * column) {
            return R.fail(ErrorCode.TERMINAL_LOADTICKETS_HPID);
        }
        //TODO 后面可修改为session统一处理
        BaseTicketLoadEntity baseTicketLoadEntity = BeanUtil.copyProperties(reqTicketLoad, BaseTicketLoadEntity.class);
        String baseTicketLoadEntityDvKey = StrUtil.format(RedisConstants.BaseKey.DATA_VERSION.getCode(),
                DbUtils.getDbTable(BaseTicketLoadEntity.class).name(),
                String.join(":", baseTicketLoadEntity.getDevNo(), baseTicketLoadEntity.getHpId() + "", baseTicketLoadEntity.getTicketId()));
        baseTicketLoadEntity.setDataVersion(commonService.getDataVersion(baseTicketLoadEntityDvKey));

        redisService.rpush(RedisConstants.BaseKey.DB_LIST.getCode() + DbUtils.getDbTable(BaseTicketLoadEntity.class).name(), JSON.toJSONString(baseTicketLoadEntity));
        String baseTicketLoadCacheKey = StrUtil.format(RedisConstants.BaseKey.BASE_TICKET_LOAD.getCode(), baseTicketLoadEntity.getDevNo());
        redisService.setCacheMapValue(baseTicketLoadCacheKey, baseTicketLoadEntity.getHpId().toString(), baseTicketLoadEntity);
        return R.ok();
    }

    @Override
    public R showList(ReqShowList reqShowList) {
        R r = commonService.sellAuthCheck(reqShowList.getDevNo());
        if (r.isFail()) {
            return r;
        }
        Map<String, BaseTicketLoadEntity> baseTicketLoadEntityMap = commonService.getTicketLoadMap(reqShowList.getDevNo());
        return R.ok(baseTicketLoadEntityMap.entrySet().stream().sorted(Map.Entry.comparingByKey()).map(x -> {
                    BaseTicketLoadEntity b = x.getValue();
                    BaseTicketDto baseTicketDto = commonService.getTicket(b.getTicketId());
                    TicketItem ticketItem = BeanUtil.copyProperties(baseTicketDto, TicketItem.class);
                    ticketItem.setTicketId(b.getTicketId());
                    return ResShowList.builder().hpId(b.getHpId()).total(b.getTotal()).ticket(ticketItem).build();
                })
                .collect(Collectors.toList()));
    }

    @Override
    public R order(ReqOrder reqOrder) {
        R r = commonService.sellAuthCheck(reqOrder.getDevNo());
        if (r.isFail()) {
            return r;
        }
        //判断票ID是否正确
        AuthDto authDto = (AuthDto) r.getData();
        List<Object> sellAuthCheck = authDto.getSiteAuthSellPlayList();
        if (!sellAuthCheck.contains(reqOrder.getTicketId())) {
            return R.fail(ErrorCode.TERMINAL_LOADTICKETS_TICKETID);
        }
        // 判断票余量是否充足
        BaseTicketLoadEntity baseTicketLoadEntity = commonService.getBaseTicketLoad(reqOrder.getDevNo(), reqOrder.getHpId() + "");
        if (Objects.isNull(baseTicketLoadEntity) || baseTicketLoadEntity.getTotal() < reqOrder.getNumber()) {
            return R.fail(ErrorCode.TERMINAL_ORDER_TICKET_COUNT);
        }
        baseTicketLoadEntity.setTotal(baseTicketLoadEntity.getTotal() - reqOrder.getNumber());
        String baseTicketLoadKey = StrUtil.format(RedisConstants.BaseKey.BASE_TICKET_LOAD.getCode(), baseTicketLoadEntity.getDevNo());


        BaseTicketDto baseTicketDto = commonService.getTicket(reqOrder.getTicketId());
        // 票面金额是否正确
        Long value = baseTicketDto.getValue();
        if (value * reqOrder.getNumber() != reqOrder.getMoney()) {
            return R.fail(ErrorCode.TERMINAL_ORDER_MONEY);
        }

        //TODO 后期接支付可此处创建账单
        //TODO 后面可修改为session统一处理
        BaseOrderEntity baseOrderEntity = createOrderEntity(authDto, reqOrder);
        String baseOrderEntityDvKey = StrUtil.format(RedisConstants.BaseKey.DATA_VERSION.getCode(), baseOrderEntity.getOrderNo());
        baseOrderEntity.setDataVersion(commonService.getDataVersion(baseOrderEntityDvKey));
        redisService.rpush(RedisConstants.BaseKey.DB_LIST.getCode() + DbUtils.getDbTable(BaseOrderEntity.class).name(), JSON.toJSONString(baseOrderEntity));
        redisService.setCacheMapValue(RedisConstants.BaseKey.BASE_ORDER.getCode(), baseOrderEntity.getOrderNo(), baseOrderEntity);


        String baseTicketLoadEntityDvKey = StrUtil.format(RedisConstants.BaseKey.DATA_VERSION.getCode(),
                DbUtils.getDbTable(BaseTicketLoadEntity.class).name(),
                String.join(":", baseTicketLoadEntity.getDevNo(), baseTicketLoadEntity.getHpId() + "", baseTicketLoadEntity.getTicketId()));
        baseTicketLoadEntity.setDataVersion(commonService.getDataVersion(baseTicketLoadEntityDvKey));
        //TODO 减库存
        redisService.setCacheMapValue(baseTicketLoadKey, baseTicketLoadEntity.getHpId().toString(), baseTicketLoadEntity);
        redisService.rpush(RedisConstants.BaseKey.DB_LIST.getCode() + DbUtils.getDbTable(BaseTicketLoadEntity.class).name(), JSON.toJSONString(baseTicketLoadEntity));


        //TODO 测试版本直接返回支付界面，正常需要进行
        return R.ok(ResOrder.builder()
                .orderQrCode(QrCodeUtil.getQrCodeUrl(reqOrder.getMoney(), baseOrderEntity.getOrderNo()))
                .orderTime(baseOrderEntity.getOrderTime())
                .devNo(reqOrder.getDevNo())
                .orderTimeOut(baseOrderEntity.getOrderTimeOut()).build());
    }

    @Override
    public R payNotify(String orderNo) {
        BaseOrderEntity baseOrderEntity = commonService.getBaseOrderEntity(orderNo);
        //订单是否存在
        if (Objects.isNull(baseOrderEntity)) {
            R r = R.fail(ErrorCode.TERMINAL_PAY_NOTIFY_ORDER_DOES_NOT_EXIST);
            log.info("{} -- req={} -- res={}", "payNotify", orderNo, JSON.toJSONString(r));
            return r;
        }
        //订单是否超时
        if (System.currentTimeMillis() > baseOrderEntity.getOrderTimeOut()) {
            R r = R.fail(ErrorCode.TERMINAL_PAY_NOTIFY_ORDER_TIMEOUT);
            log.info("{} -- req={} -- res={}", "payNotify", orderNo, JSON.toJSONString(r));
            return r;
        }
        //修改订单支付状态
        baseOrderEntity.setPayStatus(EnumPayStatus.SUCCESS.getCode());
        baseOrderEntity.setPayTime(System.currentTimeMillis());
        String baseOrderEntityDvKey = StrUtil.format(RedisConstants.BaseKey.DATA_VERSION.getCode(), baseOrderEntity.getOrderNo());
        baseOrderEntity.setDataVersion(commonService.getDataVersion(baseOrderEntityDvKey));
        redisService.setCacheMapValue(RedisConstants.BaseKey.BASE_ORDER.getCode(), baseOrderEntity.getOrderNo(), baseOrderEntity);
        redisService.rpush(RedisConstants.BaseKey.DB_LIST.getCode() + DbUtils.getDbTable(BaseOrderEntity.class).name(), JSON.toJSONString(baseOrderEntity));
        return R.ok();
    }

    @Override
    public R payResult(ReqPayResult reqPayResult) {
        BaseOrderEntity baseOrderEntity = commonService.getBaseOrderEntity(reqPayResult.getOrderNo());
        //订单是否存在
        if (Objects.isNull(baseOrderEntity)) {
            return R.fail(ErrorCode.TERMINAL_PAY_RESULT_ORDER_DOES_NOT_EXIST);
        }
        return baseOrderEntity.getPayStatus().equals(EnumPayStatus.SUCCESS.getCode()) ? R.ok() : R.fail();
    }

    @Override
    public R issueTickets(ReqIssueTickets reqIssueTickets) {
        BaseOrderEntity baseOrderEntity = commonService.getBaseOrderEntity(reqIssueTickets.getOrderNo());
        //订单是否存在
        if (Objects.isNull(baseOrderEntity)) {
            return R.fail(ErrorCode.TERMINAL_ISSUE_TICKETS_ORDER_DOES_NOT_EXIST);
        }
        if (!baseOrderEntity.getPayStatus().equals(EnumPayStatus.SUCCESS.getCode())) {
            return R.fail(ErrorCode.TERMINAL_ISSUE_TICKETS_ORDER_DOES_NOT_PAY);
        }

        //修改订单支付状态
//        baseOrderEntity.setTicketNo(reqIssueTickets.getTicketNo());
        baseOrderEntity.setOrderStatus(EnumOrderStatus.COMPLETE.getCode());
        baseOrderEntity.setBuyTime(System.currentTimeMillis());
        String baseOrderEntityDvKey = StrUtil.format(RedisConstants.BaseKey.DATA_VERSION.getCode(), baseOrderEntity.getOrderNo());
        baseOrderEntity.setDataVersion(commonService.getDataVersion(baseOrderEntityDvKey));
        redisService.setCacheMapValue(RedisConstants.BaseKey.BASE_ORDER.getCode(), baseOrderEntity.getOrderNo(), baseOrderEntity);
        redisService.rpush(RedisConstants.BaseKey.DB_LIST.getCode() + DbUtils.getDbTable(BaseOrderEntity.class).name(), JSON.toJSONString(baseOrderEntity));
        return R.ok();
    }


    @Override
    public R cashQrCode(ReqCashQrCode reqCashQrCode) {
        return R.ok(ResCashQrCode.builder().qrCodeUrl("http://" + QrCodeUtil.getInet4Address() + ":8080" + "/wxpay/index.html#/pages/cashAuth?devNo=" + reqCashQrCode.getDevNo()).build());
    }

    @Override
    public R cashAuth(String devNo, String userId) {
        redisService.setCacheMapValue(RedisConstants.BaseKey.BASE_CASH_AUTH.getCode(), devNo, userId);
        return R.ok();
    }

    @Override
    public R cashAuthResult(String devNo) {
        return R.ok(ResCashAuthResult.builder().userId(redisService.getCacheMapValue(RedisConstants.BaseKey.BASE_CASH_AUTH.getCode(), devNo).toString()).build());
    }


    @Override
    public R cash(ReqCash reqCash) {
        R r = commonService.cashAuthCheck(reqCash.getDevNo());
        if (r.isFail()) {
            return r;
        }
        //判断票ID是否正确
        AuthDto authDto = (AuthDto) r.getData();
        BaseOrgDto baseOrgDto = authDto.getBaseOrgDto();
        if (!Pattern.matches("^J\\d{39}$", reqCash.getDataArea())) {
            return R.fail(ErrorCode.TERMINAL_CASH_DATAAREA);
        }
//1: 中奖  2: 未中奖  3: 重复兑奖
        int index = new Random().nextInt(11);
        int status = (initStatus == 3) ? initStatus = 1 : ++initStatus;
        if (status != 1) {
            return R.ok(ResCash.builder().status(status).winMoney(0L).build());
        }
        List moneyList = Arrays.asList(20L, 10L, 50L, 200L, 500L, 1000L, 2000L, 20L, 10000L, 10L, 5L);
        List playNameList = Arrays.asList("幸运66-20元", "5彩钻20元", "正当红50元", "流金岁月20元", "出彩兔子10元", "好运十倍", "耀出彩20元", "喜相逢50元", "百发百中", "美梦成真", "富贵满堂5元");
        Long winMoney = (Long) moneyList.get(index);
        String playName = (String) playNameList.get(index);
        String ticketCode = reqCash.getDataArea().substring(0, 5) + "-" + reqCash.getDataArea().substring(5, 10) + "-" + reqCash.getDataArea().substring(10, 17) + "-" + reqCash.getDataArea().substring(17, 20) + "-" + reqCash.getDataArea().substring(20, 23);
        BaseCashEntity baseCashEntity = BaseCashEntity.builder()
                .devNo(reqCash.getDevNo())
                .userId(reqCash.getUserId())
                .orderNo(snowflake.nextIdStr())
                .playName(playName)
                .dataArea(reqCash.getDataArea())
                .ticketCode(ticketCode)
                .winMoney(winMoney)
                .cashTime(System.currentTimeMillis())
                .status(status).createBy(baseOrgDto.getCreateBy()).tenantId(baseOrgDto.getEnterpriseId()).build();
//        redisService.setCacheMapValue(RedisConstants.BaseKey.BASE_CASH.getCode(), baseCashEntity.getOrderNo(), baseCashEntity);
        redisService.rpush(RedisConstants.BaseKey.DB_LIST.getCode() + DbUtils.getDbTable(BaseCashEntity.class).name(), JSON.toJSONString(baseCashEntity));
        return R.ok(ResCash.builder().status(status).winMoney(winMoney).build());
    }


    private BaseOrderEntity createOrderEntity(AuthDto authDto, ReqOrder reqOrder) {
        BaseOrgDto baseOrgDto = authDto.getBaseOrgDto();
        BaseSiteDto baseSiteDto = authDto.getBaseSiteDto();
        BaseCpDto baseCpDto = authDto.getBaseCpDto();
        //创建订单--payTime--refundTime--buyTime 根据后面业务状况进行补全
        BaseOrderEntity baseOrderEntity = new BaseOrderEntity();
        String orderNo = snowflake.nextIdStr();
        baseOrderEntity.setAreaId(baseOrgDto.getAreaId());
        baseOrderEntity.setOrgNo(baseOrgDto.getOrgNo());
        baseOrderEntity.setCpNo(baseCpDto.getCpNo());
        baseOrderEntity.setSiteNo(baseSiteDto.getSiteNo());
        baseOrderEntity.setDevNo(reqOrder.getDevNo());
        baseOrderEntity.setTicketId(reqOrder.getTicketId());
        baseOrderEntity.setOrderType(EnumOrderType.TYPE_LOTT.getCode());
        baseOrderEntity.setOrderNo(orderNo);
        baseOrderEntity.setOrderMoney(reqOrder.getMoney());
        baseOrderEntity.setOrderTime(System.currentTimeMillis());
        baseOrderEntity.setOrderTimeOut(System.currentTimeMillis() + CommonContant.ORDER_OUT_TIME);
        baseOrderEntity.setOrderStatus(EnumOrderStatus.PENDING.getCode());
        baseOrderEntity.setPayType(EnumPayType.E_PAYMENT.getCode());
        baseOrderEntity.setPayStatus(EnumPayStatus.UNPAID.getCode());
        baseOrderEntity.setOrderContent(JSON.toJSONString(reqOrder));
        baseOrderEntity.setTenantId(baseOrgDto.getEnterpriseId());
        baseOrderEntity.setCreateBy(baseOrgDto.getCreateBy());
        baseOrderEntity.setSign("");
        return baseOrderEntity;
    }


}



